from datetime import datetime, timedelta, timezone
import importlib
from turtle import pd
from docx import Document
from zoneinfo import ZoneInfo
import PyPDF2
from django.core.cache import cache
import requests
from reportservice import settings
import time
import threading
import logging

logger = logging.getLogger(__name__)

def get_yida_client(company_name):
    """
    根据提供的模块名称动态导入YidaClient类。

    :param company_name: 模块名称，比如 'zhongcheng' 或 'shujian'
    :return: 导入的YidaClient类
    """
    module_name = f'yida_app_service.{company_name}.yida_config'
    module = importlib.import_module(module_name)
    return getattr(module, 'YidaClient')

def get_xm_client(company_name):
    """
    根据提供的模块名称动态导入XmCloudClient类。

    :param company_name: 模块名称，比如 'zhongcheng' 或 'shujian'
    :return: 导入的XmCloudClient类
    """
    module_name = f'yida_app_service.{company_name}.xm_cloud_config'
    module = importlib.import_module(module_name)
    return getattr(module, 'XmCloudClient')
def merge_pdfs(paths, output):
    pdf_writer = PyPDF2.PdfWriter()

    for path in paths:
        pdf_reader = PyPDF2.PdfReader(path)
        for page in range(len(pdf_reader.pages)):
            # 将每页添加到写入器对象中
            pdf_writer.add_page(pdf_reader.pages[page])

    # 写入合并的 PDF 到文件
    with open(output, 'wb') as out:
        pdf_writer.write(out)


def date_format(value):
    if not value:return ""
    try:
        date = datetime.fromtimestamp(value / 1000, timezone.utc)
        date += timedelta(hours=8)
        return date.strftime('%Y-%m-%d')
    except ValueError:
        return None
    

def timestamp_to_yida_date(timestamp_ms):
    '''将js时间戳转换成宜搭日期格式 2024-01-01'''
    if not timestamp_ms:return None
    timestamp_s = int(timestamp_ms) / 1000
    return datetime.fromtimestamp(timestamp_s,timezone.utc).strftime('%Y-%m-%d')
def timestamp_ms_to_date(timestamp_ms):
    """
    毫秒时间戳转东八区date对象
    """
    if not timestamp_ms:return None
    # 转换毫秒时间戳为秒
    timestamp_s = int(timestamp_ms) / 1000
    # 创建 datetime 对象
    datetime_obj = datetime.fromtimestamp(timestamp_s,timezone.utc)
    datetime_obj += timedelta(hours=8)
    # 返回 date 对象
    return datetime_obj.date()

def timestamp_ms_to_datetime(timestamp_ms):
    """
    毫秒时间戳转东八区datetime对象
    """
    # 转换毫秒时间戳为秒
    if not timestamp_ms:return None
    timestamp_s = timestamp_ms / 1000
    # 创建并返回 datetime 对象
    datetime_utc = datetime.fromtimestamp(timestamp_s, tz=ZoneInfo("UTC"))
    # 转换为东八区时间
    datetime_shanghai = datetime_utc.astimezone(ZoneInfo("Asia/Shanghai"))

    return datetime_shanghai

def acquire_lock(lock_key, timeout=30):
    """
    尝试获取锁，使用缓存的 add() 方法实现。超时时间默认为 5 秒。
    """
    lock_acquired = cache.add(lock_key, "locked", timeout)
    return lock_acquired

def release_lock(lock_key):
    """
    释放锁，删除缓存中的锁键。
    """
    cache.delete(lock_key)

class HTTPUtils:

    @classmethod
    def get(self, url, params,headers_config:dict={}):
        request_url = settings.XU_API_URL + url
        headers = {"Content-Type": "application/json"}
        for header_key,header_value in headers_config.items():
            headers[header_key] = header_value
        response = requests.get(request_url, params=params, headers=headers)
        if response.status_code == 200:
            return response.json()
        else:
            return None

    @classmethod
    def post(self, url, data,headers_config:dict={}):
        request_url = settings.XU_API_URL + url
        headers = {"Content-Type": "application/json"}
        for header_key,header_value in headers_config.items():
            headers[header_key] = header_value        
        response = requests.post(request_url, json=data, headers=headers)
        if response.status_code == 200:
            return response.json()
        else:
            return None    
        
def is_blank_or_nan(value):
    return value == "" or value == None or pd.isna(value)


def is_integer_or_strint(value):
    if value == None:
        return False
    return type(value) == int or type(value) == float or str.isdigit(value)        

def write_file(file_path:str,content,mode='a+',write_error_logger=None):
    try:
        # 使用with语句自动管理文件的打开和关闭
        with open(file_path, mode=mode) as file:
            file.write(content + '\n')
    except Exception as error:
        logger.error(f"写入文件 {file_path} 失败！具体原因：{error}")
        # 记录哪些内容写入失败了
        if write_error_logger:
            write_error_logger.error(content)

'''同步数据使用的redis分布式锁'''
'''全状态锁'''

class SyncHandleRedisLock:

    def __init__(self, lock_name, expire=12,renew_sleep_count=3):
        self.lock_name = lock_name
        self.expire = expire
        self.lock_value = 1  # 生成唯一的锁值
        self.renew_thread = None
        self.event = threading.Event() # 使用event来保证可见性
        self.renew_sleep_count = renew_sleep_count # 睡眠分几次进行，这是为了提早结束续签线程

    def _renew_lock(self):
        while not self.event.is_set():
            var_sleep_count = self.renew_sleep_count
            half_expire = self.expire // 2
            # 分多次sleep，能够提前结束线程处理，建议每次睡眠时间大于等于2s
            while var_sleep_count > 0:
                if self.event.is_set():
                    logger.debug("续签线程周期开始前结束")                    
                    return
                time.sleep(half_expire / self.renew_sleep_count)
                # 检验事件状态是否被改变
                if self.event.is_set():
                    logger.debug("续签线程周期进行中结束")                    
                    return
                var_sleep_count -= 1
            # 检验事件状态是否被改变
            if self.event.is_set():
                logger.debug("续签线程周期进行后结束")                
                return
            logger.debug(f"续签线程进行续签")
            cache.set(self.lock_name, self.lock_value,timeout=self.expire)

    def acquire(self):
        if cache.add(self.lock_name, self.lock_value, timeout=self.expire):
            self.renew_thread = threading.Thread(target=self._renew_lock)
            self.renew_thread.start()
            return True
        return False
    
    # 获取锁有周期和次数重试
    def acquire_loop(self,get_period=6,get_count=5):
        while get_count > 0:
            # 尝试获取锁
            if self.acquire():
                return True
            else:
                get_count -= 1
                time.sleep(get_period)
        return False

    def release(self):
        # 这里应该保证是原子操作
        if cache.get(self.lock_name) == self.lock_value:
            self.event.set()
            self.renew_thread.join()  # 确保续签线程结束再释放锁
            logger.debug(f"{self.lock_name}释放锁") 
            cache.delete(self.lock_name)

'''安全的字典类，用于多线程读写操作'''
class SafeDict:
    def __init__(self):
        self.data = {}
        self.lock = threading.Lock()

    def get(self, key):
        with self.lock:
            return self.data.get(key)

    def set(self, key, value):
        with self.lock:
            # !判断是否存在了该key
            if key in self.data:
                logger.debug(f"已经存在相同key:{key}")
                return False
            self.data[key] = value
            return True

    def delete(self, key):
        with self.lock:
            if key in self.data:
                del self.data[key]